<!DOCTYPE html>
<html lang='zh-CN'>
  <head>
    <meta charset='UTF-8'>
    <meta name='viewport' content='width=device-width,initial-scale=1'>
    <title>md5</title>
  </head>
  <body>
    <input type='file' id='files'>
    <script id='spark-md5' type='worker/spark-md5'>
      self.importScripts('http://cdn.staticfile.org/spark-md5/3.0.2/spark-md5.min.js');
      self.addEventListener('message', function (event) {
        let blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice,
          file = event.data,
          chunkSize = 10 * 1024 * 1024,
          chunks = Math.ceil(file.size / chunkSize),
          currentChunk = 0,
          spark = new SparkMD5.ArrayBuffer(),
          fileReader = new FileReader();

        fileReader.onload = function (e) {
          console.info('read chunk nr', currentChunk + 1, 'of', chunks);
          spark.append(e.target.result);
          currentChunk++;

          if (currentChunk < chunks) {
            loadNext();
          } else {
            self.postMessage(spark.end());
          }
        };

        function loadNext() {
          let start = currentChunk * chunkSize,
            end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize;
          fileReader.readAsArrayBuffer(blobSlice.call(file, start, end));
        }
        loadNext();
      }, false);
    </script>

    <script id='crypto-js' type='worker/crypto-js'>
      self.importScripts('http://cdn.staticfile.org/crypto-js/4.1.1/crypto-js.min.js');
      self.onmessage = function (event) {
        let blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice,
          file = event.data,
          chunkSize = 10 * 1024 * 1024,
          chunks = Math.ceil(file.size / chunkSize),
          currentChunk = 0,
          md5 = CryptoJS.algo.MD5.create(),
          sha1 = CryptoJS.algo.SHA1.create(),
          sha256 = CryptoJS.algo.SHA256.create(),
          fileReader = new FileReader();

        fileReader.onload = function (e) {
          console.info('read chunk nr', currentChunk + 1, 'of', chunks);
          let wordArray = CryptoJS.lib.WordArray.create(fileReader.result);
					md5.update(wordArray);
          sha1.update(wordArray);
          sha256.update(wordArray);
          currentChunk++;

          if (currentChunk < chunks) {
            loadNext();
          } else {
            self.postMessage(md5.finalize().toString());
            self.postMessage(sha256.finalize().toString());
            self.postMessage(sha1.finalize().toString(CryptoJS.enc.Hex));
            self.close();
          }
        };

        function loadNext() {
          let start = currentChunk * chunkSize,
            end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize;
          fileReader.readAsArrayBuffer(blobSlice.call(file, start, end));
        }
        loadNext();
      };
    </script>
  </body>
  <script>
    const spark_md5_blob = new Blob([document.querySelector('#spark-md5').textContent]);
    const spark_md5_url = window.URL.createObjectURL(spark_md5_blob);
    const spark_md5_worker = new Worker(spark_md5_url, {name: 'spark_md5_worker'});
    spark_md5_worker.onmessage = function (event) {
      console.info(event.data);
      spark_md5_worker.terminate();
    };

    const crypto_js_blob = new Blob([document.querySelector('#crypto-js').textContent]);
    const crypto_js_url = window.URL.createObjectURL(crypto_js_blob);
    const crypto_js_worker = new Worker(crypto_js_url, {name: 'crypto_js_worker'});
    crypto_js_worker.onmessage = function (event) {
      console.info(event.data);
    };

    document.querySelector('#files').addEventListener('change', event => {
      const file = event.target.files[0];
      spark_md5_worker.postMessage(file);
      crypto_js_worker.postMessage(file);
    });
  </script>
</html>